package middleware

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"go-admin/global"
	"go-admin/pkg/app"
)

const (
	ValidationFail          = 4000 // 校验失败
	TokenExpired            = 4001 // 普通token过期
	RefreshTokenExpired     = 4002 // 刷新token过期
	ValidationInterfaceFail = 4003 // 接口权限异常
)

// 校验jwt中间件
func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		response := app.NewResponse(c)
		// 校验用户是否携带token
		headerToken := app.GetToken(c)
		if headerToken == "" {
			response.Resp(ValidationFail, app.WithMsg("请求不存在有效凭证"))
			response.Ctx.Abort()
			return
		}

		// 解析token
		token, err := app.ParseToken(headerToken)
		claims, ok := token.Claims.(*app.MyClaims)
		if !ok {
			response.Resp(ValidationFail, app.WithMsg("请求不存在有效凭证"))
			response.Ctx.Abort()
			return
		}
		if err != nil {
			if ve, ok := err.(*jwt.ValidationError); ok {
				switch ve.Errors {
				case jwt.ValidationErrorExpired: // 判断是否过期
					// 判断当前是普通token还是刷新token
					if claims.IsRefreshToken { // 刷新token，生成新的请求token和刷新token返回
						response.Resp(RefreshTokenExpired, app.WithMsg("刷新token已过期"))
						response.Ctx.Abort()
						return
					} else { // 校验请求token是否有效
						response.Resp(TokenExpired, app.WithMsg("请求token已过期"))
						response.Ctx.Abort()
						return
					}
				default:
					response.Resp(ValidationFail, app.WithMsg("请求不存在有效凭证"))
					response.Ctx.Abort()
					return
				}
			} else {
				response.Resp(ValidationFail, app.WithMsg("请求不存在有效凭证"))
				response.Ctx.Abort()
				return
			}
		}

		// 判断是否有接口权限
		// 加载策略
		if err = global.Enforcer.LoadPolicy(); err != nil {
			response.Resp(ValidationFail, app.WithMsg("加载权限异常"))
			response.Ctx.Abort()
			return
		}

		enforce, _ := global.Enforcer.Enforce(claims.Username, c.Request.URL.Path, c.Request.Method)
		if enforce {
			// 将当前请求的token解析对象存放到上下文中
			response.Ctx.Set("myClaims", claims)
			c.Next()
		} else {
			response.Resp(ValidationInterfaceFail, app.WithMsg("您没有该接口的权限"))
			response.Ctx.Abort()
			return
		}

	}
}
